home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Source.bin / ComboBox.java < prev    next >
Text File  |  1998-09-23  |  54KB  |  1,747 lines

  1. package symantec.itools.awt;
  2.  
  3. import java.awt.Color;
  4. import java.awt.Component;
  5. import java.awt.Dimension;
  6. import java.awt.Font;
  7. import java.awt.Graphics;
  8. import java.awt.Image;
  9. import java.awt.Panel;
  10. import java.awt.TextField;
  11. import java.awt.LayoutManager;
  12. import java.awt.AWTEvent;
  13. import java.awt.AWTEventMulticaster;
  14. import java.awt.event.MouseEvent;
  15. import java.awt.event.FocusEvent;
  16. import java.awt.event.ActionEvent;
  17. import java.awt.event.ActionListener;
  18. import java.awt.event.ItemEvent;
  19. import java.awt.event.KeyEvent;
  20. import java.beans.PropertyVetoException;
  21. import java.beans.PropertyChangeListener;
  22. import java.beans.VetoableChangeListener;
  23. import symantec.itools.beans.VetoableChangeSupport;
  24. import symantec.itools.beans.PropertyChangeSupport;
  25.  
  26. //    01/29/97    TWB    Integrated changes from Macintosh
  27. //    04/15/97    LAB Added 1 line in deselect() to clear
  28. //                    the textbox if deselect is called.
  29. //  05/20/97    CAR Changed handleEvent for the following cases:
  30. //                  removed case for Event.KEY_ACTION_RELEASE
  31. //                  case Event.KEY_PRESS checks for ENTER key
  32. //                  case Event.ACTION_EVENT has the list request focus if it is dropped
  33. //                  case Event.LIST_SELECT does not "undrop" the list while selection is
  34. //                  being made with keys
  35. //  05/21/97    CAR Changed handleEvent to hide list if it loses focus.
  36. //                  Changed Event.LOST_FOCUS to not hide list if the arrow
  37. //                  loses focus while the pointer is not over the list.
  38. //    05/30/97    RKM    Made it compile with some of the 1.1 component changes (added catches)
  39. //    06/06/97    LAB    Updated to support Java 1.1
  40. //    06/11/97    LAB    Fixed setText(String) and getText() to be for the EditBox and setListText(int, String)
  41. //                    and getListText(int) to be for the List.
  42. //    07/11/97    LAB    Updated calls to the deprecated methods enable() and disable() in DirectionButton
  43. //                    to the new call setEnabled(boolean).
  44. //    07/13/97    RKM    Changed implementations of getPreferredSize & getMinimumSize
  45. //                    Extracted reshapes from paint override into reshapeInternals
  46. //                    Added call to reshapeInternals inside of reshape override
  47. //                    Changed the way getters & setters for font properties worked
  48. //                    Removed Font variables, used getFont instead (fixed getFont returned null if not set bug)
  49. //    07/14/97    RKM    Height of editText is always preferred height
  50. //                    Removed EVT_IMAGE_SELECT (it's not used)
  51. //                    Hid the list before adding it (why take the change of flicker?)
  52. //                    Added setLayout override so users could not change layout on us
  53. //                    Eliminated misc font properties, used Component's font
  54. //                    Eliminated DropDownFont property
  55. //                    Eliminated EditFieldFont property
  56. //                    Eliminated ComboBoxFont property
  57. //                    Changed bOsFlag to be not a Mac, I think the original developer wanted to check for Solaris
  58. //    07/15/97    RKM    Directionbutton is screwed on expand until I can get a descent preferredSize from it
  59. //    07/19/97    LAB    Added add/removeNotify for event listener registration.
  60. //    07/19/97    RKM    Changed addLastBottomUp, added case for Macintosh
  61. //                    Moved addLastBottomUp into isFirstDrawnOverSecond in ZOrderUtils
  62. //  07/30/97    CAR marked fields transient as needed
  63. //                  inner adaptor classes implement java.io.Serializable
  64. //                  unable to completely test serializablity in BeanBox as drop down will not work
  65. //  10/01/97    LAB Changed setListItems to call list.clear() instead of clear() to prevent
  66. //                    the text in the text area from being deleted (Addresses Mac Bug #7995).
  67. //                    Changed names of strings in PropertyChangeEvent handling to follow Bean Spec
  68. //                    naming conventions.  Made searchable work (Addresses Mac Bug #8000).
  69. //                    Removed Macintosh specific code to deal with textbox offset problem in MRJ.
  70. //                    Fixed default state problem causing vertical scroll bar never to appear
  71. //                    (Addresses Mac Bug #7538).Added code to more gracefully handle the case
  72. //                    when the combobox list doesn't have enough room to extend fully.
  73. //  10/03/97    LAB Made getPreferredSize calculate the size it should be to see the largest item
  74. //                    in the list.
  75.  
  76. /**
  77.  * A ComboBox is a text field with an attached drop-down list box. It may be
  78.  * user-editable, "searchable", have horizontal and/or vertical scroll
  79.  * bars, and can use different fonts for the text box and the drop-down list.
  80.  * Also each list box item can have an image in addition to text.
  81.  * A user-editable ComboBox allows the user to enter any desired text into
  82.  * the text field. A searchable ComboBox allows the user to enter text into
  83.  * the text field as long as it matches one of the existing list items.
  84.  * This allows the user to select from a non-editable list by typing instead
  85.  * of dropping-down the list and selecting with the mouse.
  86.  * <p>
  87.  * Use a ComboBox to:
  88.  * <UL>
  89.  * <LI>Compactly provide a list of items for the user to select from.
  90.  * <LI>Have a text field that maintains a history of what's been entered in it.
  91.  * <LI>Allow the user to either select from a list or enter a new value.
  92.  * </UL>
  93.  * @version 1.1, June 6, 1997
  94.  * @author Symantec
  95.  */
  96. public class ComboBox extends Panel
  97. {
  98.     /**
  99.      * Constructs a new default ComboBox. The ComboBox is not editable and
  100.      * not searchable by default.
  101.      */
  102.     public ComboBox()
  103.     {
  104.         this(false, false);
  105.     }
  106.  
  107.     /**
  108.      * Constructs a new editable and/or searchable ComboBox.
  109.      * @param editable true = editable, false = non-editable
  110.      * @param searchable true = searchable, false = non-searchable
  111.      */
  112.     public ComboBox(boolean editable, boolean searchable)
  113.     {
  114.         vPad = 0;
  115.         hPad = 1;
  116.  
  117.         super.setLayout(null);
  118.  
  119.         editBox = new TextField("");
  120.         editBox.setEditable(false);
  121.         editBox.setBackground(Color.white);
  122.  
  123.         arrow = new DirectionButton(DirectionButton.DOWN);
  124.         try
  125.         {
  126.             arrow.setShowFocus(false);
  127.         }
  128.         catch(java.beans.PropertyVetoException veto) {}
  129.         arrow.setEnabled(false);
  130.  
  131.         list = new ImageListBox("ILB");
  132.         list.hide();
  133.         try
  134.         {
  135.             list.setComboMode(true);
  136.             list.setShowHorizontalScroll(false);
  137.             list.setShowVerticalScroll(true);
  138.         }
  139.         catch(PropertyVetoException e) {}
  140.  
  141.         add(list);
  142.         add(editBox);
  143.         add(arrow);
  144.  
  145.         lheight = 0;
  146.  
  147.         try
  148.         {
  149.             setEditable(editable);
  150.             setSearchable(searchable);
  151.         }
  152.         catch(java.beans.PropertyVetoException veto) {}
  153.         bCaseSensitive = true;
  154.     }
  155.  
  156.     /**
  157.      * Conditionally sets the ComboBox to be user-editable.
  158.      * @param editable true = editable, false = non-editable
  159.      * @exception PropertyVetoException
  160.      * if the specified property value is unacceptable
  161.      * @see #isEditable
  162.      */
  163.     public void setEditable(boolean editable) throws PropertyVetoException
  164.     {
  165.         if(bEditable != editable)
  166.         {
  167.             Boolean oldValue = new Boolean(bEditable);
  168.             Boolean newValue = new Boolean(editable);
  169.  
  170.             vetos.fireVetoableChange("editable", oldValue, newValue);
  171.  
  172.             bEditable = editable;
  173.             editBox.setEditable(bEditable || bSearchable);
  174.  
  175.             changes.firePropertyChange("editable", oldValue, newValue);
  176.         }
  177.     }
  178.  
  179.     /**
  180.      * Gets whether the ComboBox is user-editable.
  181.      * @return true if it is user-editable, false otherwise
  182.      * @see #setEditable
  183.      */
  184.     public boolean isEditable()
  185.     {
  186.         return bEditable;
  187.     }
  188.  
  189.     /**
  190.      * @deprecated
  191.      * @see #isEditable
  192.      */
  193.     public boolean getEditable()
  194.     {
  195.         return isEditable();
  196.     }
  197.  
  198.     /**
  199.      * Conditionally sets the ComboBox to be searchable.
  200.      * A searchable ComboBox allows the user to enter text into
  201.      * the text field as long as it matches one of the existing list items.
  202.      * This allows the user to select from a non-editable list by typing instead
  203.      * of dropping-down the list and selecting with the mouse.
  204.      * @param searchable true = searchable, false = non-searchable
  205.      * @exception PropertyVetoException
  206.      * if the specified property value is unacceptable
  207.      * @see #isSearchable
  208.      */
  209.     public void setSearchable(boolean searchable) throws PropertyVetoException
  210.     {
  211.         if(bSearchable != searchable)
  212.         {
  213.             Boolean oldValue = new Boolean(bSearchable);
  214.             Boolean newValue = new Boolean(searchable);
  215.  
  216.             vetos.fireVetoableChange("searchable", oldValue, newValue);
  217.  
  218.             bSearchable = searchable;
  219.             editBox.setEditable(bEditable || bSearchable);
  220.  
  221.             changes.firePropertyChange("searchable", oldValue, newValue);
  222.         }
  223.     }
  224.  
  225.     /**
  226.      * Returns the current ComboBox "searchable" status.
  227.      * A searchable ComboBox allows the user to enter text into
  228.      * the text field as long as it matches one of the existing list items.
  229.      * This allows the user to select from a non-editable list by typing instead
  230.      * of dropping-down the list and selecting with the mouse.
  231.      * @see #setSearchable
  232.      */
  233.     public boolean isSearchable()
  234.     {
  235.         return bSearchable;
  236.     }
  237.  
  238.     /**
  239.      * @deprecated
  240.      * @see #isSearchable
  241.      */
  242.     public boolean getSearchable()
  243.     {
  244.         return isSearchable();
  245.     }
  246.  
  247.     /**
  248.      * Conditionally set the ComboBox to be case sensitive during searches.
  249.      * @param bCaseSensitive true = case-sensitive, false = case-insensitive
  250.      * @exception PropertyVetoException
  251.      * if the specified property value is unacceptable
  252.      * @see #getCaseSensitive
  253.      */
  254.     public void setCaseSensitive(boolean bCaseSensitive) throws PropertyVetoException
  255.     {
  256.         if (this.bCaseSensitive != bCaseSensitive)
  257.         {
  258.                Boolean oldValue = new Boolean(this.bCaseSensitive);
  259.             Boolean newValue = new Boolean(bCaseSensitive);
  260.  
  261.             vetos.fireVetoableChange("caseSensitive", oldValue, newValue);
  262.  
  263.             this.bCaseSensitive = bCaseSensitive;
  264.  
  265.             changes.firePropertyChange("caseSensitive", oldValue, newValue);
  266.         }
  267.     }
  268.  
  269.     /**
  270.      * Returns the current ComboBox case-sensitive search status.
  271.      * @see #setSearchable
  272.      */
  273.     public boolean isCaseSensitive()
  274.     {
  275.         return bCaseSensitive;
  276.     }
  277.  
  278.     /**
  279.      * @deprecated
  280.      * @see #isSearchable
  281.      */
  282.     public boolean getCaseSensitive()
  283.     {
  284.         return isCaseSensitive();
  285.     }
  286.  
  287.     /**
  288.      * Sets whether or not the horizontal scrollbar should be made visible when
  289.      * necessary or should never be made visible.
  290.      * @param cond true = show when necessary, false = never show
  291.      * @exception PropertyVetoException
  292.      * if the specified property value is unacceptable
  293.      * @see #isShowHorizontalScroll
  294.      */
  295.     public void setShowHorizontalScroll(boolean cond) throws PropertyVetoException
  296.     {
  297.         if(showHScroll != cond)
  298.         {
  299.             Boolean oldValue = new Boolean(showHScroll);
  300.             Boolean newValue = new Boolean(cond);
  301.  
  302.             vetos.fireVetoableChange("showHorizontalScroll", oldValue, newValue);
  303.  
  304.             showHScroll = cond;
  305.             list.setShowHorizontalScroll(cond);
  306.  
  307.             changes.firePropertyChange("showHorizontalScroll", oldValue, newValue);
  308.         }
  309.     }
  310.  
  311.     /**
  312.      * Gets the current horizontal scrollbar display option.
  313.      * @return true if the horizontal scrollbar should be displayed when necessary,
  314.      * false if the scrollbar should never be shown
  315.      * @see #setShowHorizontalScroll
  316.      */
  317.     public boolean isShowHorizontalScroll()
  318.     {
  319.         return showHScroll;
  320.     }
  321.  
  322.     /**
  323.      * @deprecated
  324.      * @see #isShowHorizontalScroll
  325.      */
  326.     public boolean getShowHorizontalScroll()
  327.     {
  328.         return isShowHorizontalScroll();
  329.     }
  330.  
  331.     /**
  332.      * Sets whether or not the vertical scrollbar should be made visible when
  333.      * necessary or should never be made visible.
  334.      * @param cond true = show when necessary, false = never show
  335.      * @exception PropertyVetoException
  336.      * if the specified property value is unacceptable
  337.      * @see #isShowVerticalScroll
  338.      */
  339.     public void setShowVerticalScroll(boolean cond) throws PropertyVetoException
  340.     {
  341.         if(showVScroll != cond)
  342.         {
  343.             Boolean oldValue = new Boolean(showVScroll);
  344.             Boolean newValue = new Boolean(cond);
  345.  
  346.             vetos.fireVetoableChange("showVerticalScroll", oldValue, newValue);
  347.  
  348.             showVScroll = cond;
  349.             list.setShowVerticalScroll(cond);
  350.  
  351.             changes.firePropertyChange("showVerticalScroll", oldValue, newValue);
  352.         }
  353.     }
  354.  
  355.     /**
  356.      * Gets the current vertical scrollbar display option.
  357.      * @return true if the vertical scrollbar should be displayed when necessary,
  358.      * false if the scrollbar should never be shown
  359.      * @see #setShowVerticalScroll
  360.      */
  361.     public boolean isShowVerticalScroll()
  362.     {
  363.         return showVScroll;
  364.     }
  365.  
  366.     /**
  367.      * @deprecated
  368.      * @see #isShowVerticalScroll
  369.      */
  370.     public boolean getShowVerticalScroll()
  371.     {
  372.         return isShowVerticalScroll();
  373.     }
  374.  
  375.     /**
  376.      * Adds the string array to the list.
  377.      * @param items items to add to the list
  378.      * @exception PropertyVetoException
  379.      * if the specified property value is unacceptable
  380.      * @see #getListItems
  381.      * @see #addItem(java.lang.String)
  382.      * @see #addItem(java.lang.String, boolean)
  383.      * @see #addItem(java.awt.Image, java.lang.String)
  384.      * @see #addItem(java.awt.Image, java.lang.String, boolean)
  385.      */
  386.     public void setListItems(String[] items) throws PropertyVetoException
  387.     {
  388.         String[] oldValue = getListItems();
  389.  
  390.         if(!symantec.itools.util.GeneralUtils.objectsEqual(oldValue, items))
  391.         {
  392.             vetos.fireVetoableChange("listItems", oldValue, items);
  393.  
  394.             list.clear();
  395.             for (int i = 0; i < items.length; ++i)
  396.             {
  397.                 addItem(items[i]);
  398.             }
  399.             updateMaxNumChars();
  400.  
  401.             changes.firePropertyChange("listItems", oldValue, items);
  402.         }
  403.     }
  404.  
  405.     /**
  406.      * Returns the current list as an array.
  407.      * @see #setListItems
  408.      */
  409.     public String[] getListItems()
  410.     {
  411.         int len = countItems();
  412.  
  413.         String[] items = new String[len];
  414.  
  415.         for (int i = 0; i < len; ++i)
  416.             items[i] = getItem(i);
  417.  
  418.         return items;
  419.     }
  420.  
  421.     /**
  422.      * Sets the font of the component.
  423.      * @param f the font
  424.      * @see java.awt.Component#getFont
  425.      */
  426.     public synchronized void setFont(Font newFont)
  427.     {
  428.         super.setFont(newFont);
  429.  
  430.         editBox.setFont(newFont);
  431.         list.setFont(newFont);
  432.  
  433.         repaint();
  434.     }
  435.  
  436.     /**
  437.      * @deprecated
  438.      * @see #getListText(int)
  439.      */
  440.     public String getItem(int index)
  441.     {
  442.         return getListText(index);
  443.     }
  444.  
  445.     /**
  446.      * Returns the text associated with a drop-down item.
  447.      * @return the text associated with the drop-down item at index
  448.      * @see #setListText(int, java.lang.String)
  449.      */
  450.     public String getListText(int index)
  451.     {
  452.         return list.getText(index);
  453.     }
  454.  
  455.     /**
  456.      * Sets the text in the edit field portion of the ComboBox
  457.      * is not editable.
  458.      * @param text to replace the text of the EditBox
  459.      * @exception PropertyVetoException
  460.      * if the specified property value is unacceptable
  461.      * @see #getSelectedItem
  462.      */
  463.     public void setText(String newText) throws java.beans.PropertyVetoException
  464.     {
  465.         String oldValue = getText();
  466.         if(!symantec.itools.util.GeneralUtils.objectsEqual(oldValue, newText))
  467.         {
  468.             vetos.fireVetoableChange("text", oldValue, newText);
  469.  
  470.             editBox.setText(newText);
  471.  
  472.             changes.firePropertyChange("text", oldValue, newText);
  473.         }
  474.     }
  475.  
  476.     /**
  477.      * Returns the text in the edit field portion of the ComboBox, unless the ComboBox
  478.      * is not editable.
  479.      * @return the edit field text if editable, or null if this ComboBox is not editable
  480.      * @see #getSelectedItem
  481.      */
  482.     public String getText()
  483.     {
  484.         verify();
  485.         return editBox.getText();
  486.     }
  487.  
  488.     /**
  489.      * Returns the selected item on the drop-down list.
  490.      * @return the text of the selected item, or null if no item is selected
  491.      * @see #getText
  492.      * @see #getSelectedIndex
  493.      */
  494.     public String getSelectedItem()
  495.     {
  496.         return list.getSelectedItem();
  497.     }
  498.  
  499.     /**
  500.      * Gets the zero-relative index of the currently selected item in the drop-down list.
  501.      * @return the zero-relative index of the current selection, or -1 if no item is selected
  502.      * @see #getSelectedItem
  503.      */
  504.     public int getSelectedIndex()
  505.     {
  506.         return list.getSelectedIndex();
  507.     }
  508.  
  509.     /**
  510.      * Returns the selection state of the list item at the given zero-relative index.
  511.      * @param index the zero-relative index of the drop-down list item to be checked
  512.      * @return true if the drop-down list item at the specified index has been
  513.      * selected; false otherwise
  514.      * @see #select
  515.      */
  516.     public synchronized boolean isSelected(int index)
  517.     {
  518.         return list.isSelected(index);
  519.     }
  520.  
  521.     /**
  522.      * Determines whether the ComboBox should be the first component added to
  523.      * its container, or the last. This varies from system to system depending
  524.      * on the native user interface. If this method returns true, add the
  525.      * ComboBox before adding other components. If it returns false, add other
  526.      * components before adding the ComboBox. If the ComboBox is added in the
  527.      * wrong order, the drop-down list box will be drawn under the other
  528.      * components instead of on top of them.
  529.      * @return if true add the ComboBox to its container before other components,
  530.      * otherwise add after all other components
  531.      * @see #addLastBottomUp
  532.      */
  533.     public static boolean addFirstTopDown()
  534.     {
  535.         return !addLastBottomUp();
  536.     }
  537.  
  538.     /**
  539.      * Determines whether the ComboBox should be the last component added to
  540.      * its container, or the first. This varies from system to system depending
  541.      * on the native user interface. If this method returns true, add the
  542.      * ComboBox after adding other components. If it returns false, add other
  543.      * components after adding the ComboBox. If the ComboBox is added in the
  544.      * wrong order, the drop-down list box will be drawn under the other
  545.      * components instead of on top of them.
  546.      * @return if true add the ComboBox to its container after other components,
  547.      * otherwise add before all other components
  548.      * @see #addFirstTopDown
  549.      */
  550.     public static boolean addLastBottomUp()
  551.     {
  552.         return symantec.itools.util.ZOrderUtils.isFirstDrawnOverSecond();
  553.     }
  554.  
  555.     /**
  556.      * Use this method to set a flag for use in your handleEvent to determine if
  557.      * the ComboBox needs help in "un-dropping".  This will improve useability
  558.      * under platforms which do not provide proper focus events.  For best
  559.      * performance assign a variable in your class once to avoid repeated function
  560.      * calls to this method, like this:
  561.      * <pre>
  562.      *   boolean bNeedsPlatformHelp = ComboBox.needsPlatformHelp();
  563.      *
  564.      *   public boolean handleEvent(Event evt)
  565.      *   {
  566.      *       switch (evt.id)
  567.      *       {
  568.      *           case Event.MOUSE_UP:
  569.      *               // do it on mouse up, which indicates a full click somewhere other than
  570.      *               // the ComboBox that could be currently dropped down.
  571.      *               if (bNeedsPlatformHelp && ComboBox.isListDown)
  572.      *                   ComboBox.setListDown(false);
  573.      *               break; // or other MOUSE_UP processing as necessary
  574.      *
  575.      *           ...
  576.      *       }
  577.      *
  578.      *       ...
  579.      *   }
  580.      * </pre>
  581.      * @see #setListDown
  582.      */
  583.     public static boolean needsPlatformHelp()
  584.     {
  585.         return bOsFlag;
  586.     }
  587.  
  588.     /**
  589.      * Clears all items from the drop-down list.
  590.      */
  591.     public void clear()
  592.     {
  593.         list.clear();
  594.         editBox.setText("");
  595.         updateMaxNumChars();
  596.     }
  597.  
  598.     /**
  599.      * Adds the specified item to the end of the drop-down list and enables the item.
  600.      * @param item the item to be added
  601.      * @exception PropertyVetoException
  602.      * if the specified property value is unacceptable
  603.      * @see #addItem(java.lang.String, boolean)
  604.      * @see #addItem(java.awt.Image, java.lang.String)
  605.      * @see #addItem(java.awt.Image, java.lang.String, boolean)
  606.      * @see #setListItems(java.lang.String[])
  607.      */
  608.     public synchronized void addItem(String item) throws PropertyVetoException
  609.     {
  610.         addItem((Image)null, item, true);
  611.     }
  612.  
  613.     /**
  614.      * Adds the specified item to the end of the drop-down list and conditionally enables it.
  615.      * @param item the item to be added
  616.      * @param bEnabled true = enable the item, false = disable it
  617.      * @exception PropertyVetoException
  618.      * if the specified property value is unacceptable
  619.      * @see #addItem(java.lang.String)
  620.      * @see #addItem(java.awt.Image, java.lang.String)
  621.      * @see #addItem(java.awt.Image, java.lang.String, boolean)
  622.      * @see #setListItems(java.lang.String[])
  623.      */
  624.     public synchronized void addItem(String item, boolean bEnabled) throws PropertyVetoException
  625.     {
  626.         addItem((Image)null, item, bEnabled);
  627.     }
  628.  
  629.     /**
  630.      * Adds the specified item with an image to the end of the drop-down list and enables it.
  631.      * @param image the image to display on the item line
  632.      * @param item the item to be added
  633.      * @exception PropertyVetoException
  634.      * if the specified property value is unacceptable
  635.      * @see #addItem(java.lang.String)
  636.      * @see #addItem(java.lang.String, boolean)
  637.      * @see #addItem(java.awt.Image, java.lang.String, boolean)
  638.      * @see #setListItems(java.lang.String[])
  639.      */
  640.     public synchronized void addItem(Image image, String item) throws PropertyVetoException
  641.     {
  642.         addItem(image, item, true);
  643.     }
  644.  
  645.     /**
  646.      * Adds the specified item with an image to the end of the drop-down list and
  647.      * conditionally enables it.
  648.      * @param image the image to display on the item line
  649.      * @param item the item to be added
  650.      * @param bEnabled true = enable the item, false = disable it
  651.      * @exception PropertyVetoException
  652.      * if the specified property value is unacceptable
  653.      * @see #addItem(java.lang.String)
  654.      * @see #addItem(java.lang.String, boolean)
  655.      * @see #addItem(java.awt.Image, java.lang.String)
  656.      * @see #setListItems(java.lang.String[])
  657.      */
  658.     public synchronized void addItem(Image image, String item, boolean bEnabled) throws PropertyVetoException
  659.     {
  660.         list.addItem(image, item, bEnabled);
  661.         arrow.setEnabled(true);
  662.         updateMaxNumChars();
  663.     }
  664.  
  665.     /**
  666.      * Returns the total number of items in the drop-down list.
  667.      */
  668.     public int countItems()
  669.     {
  670.         return list.countItems();
  671.     }
  672.  
  673.     /**
  674.      * Changes the image associated with a drop-down item.
  675.      * @param index the zero-relative index of the drop-down item
  676.      * @param image the image to associate with the drop-down item
  677.      * @exception PropertyVetoException
  678.      * if the specified property value is unacceptable
  679.      */
  680.     public void setImage(int index, Image image) throws PropertyVetoException
  681.     {
  682.         list.setImage(index, image);
  683.     }
  684.  
  685.     /**
  686.      * @deprecated
  687.      * @see #setImage(int, java.awt.Image)
  688.      * @exception PropertyVetoException
  689.      * if the specified property value is unacceptable
  690.      */
  691.     public void changeImage(int index, Image image) throws PropertyVetoException
  692.     {
  693.         setImage(index, image);
  694.     }
  695.  
  696.     /**
  697.      * Changes the text associated with a drop-down item.
  698.      * @param index the zero-relative index of the drop-down item
  699.      * @param text the text to associate with the drop-down item
  700.      * @exception PropertyVetoException
  701.      * if the specified property value is unacceptable
  702.      */
  703.     public void setListText(int index, String text) throws PropertyVetoException
  704.     {
  705.         list.setText(index, text);
  706.         updateMaxNumChars();
  707.     }
  708.  
  709.     /**
  710.      * @deprecated
  711.      * @see #setListText(int, java.lang.String)
  712.      * @exception PropertyVetoException
  713.      * if the specified property value is unacceptable
  714.      */
  715.     public void changeText(int index, String text) throws PropertyVetoException
  716.     {
  717.         setListText(index, text);
  718.     }
  719.  
  720.     /**
  721.      * Enables a drop-down list item at a given zero-relative index.
  722.      * @param index the zero-relative index of the drop-down list item
  723.      * @exception PropertyVetoException
  724.      * if the specified property value is unacceptable
  725.      */
  726.     public void setEnabled(int index) throws PropertyVetoException
  727.     {
  728.         setEnabled(index, true);
  729.     }
  730.  
  731.     /**
  732.      * @deprecated
  733.      * @see #setEnabled(int)
  734.      * @exception PropertyVetoException
  735.      * if the specified property value is unacceptable
  736.      */
  737.     public void enable(int index) throws PropertyVetoException
  738.     {
  739.         setEnabled(index);
  740.     }
  741.  
  742.     /**
  743.      * @deprecated
  744.      * @see #setEnabled(int, boolean)
  745.      * @exception PropertyVetoException
  746.      * if the specified property value is unacceptable
  747.      */
  748.     public void disable(int index) throws PropertyVetoException
  749.     {
  750.         setEnabled(index, false);
  751.     }
  752.  
  753.     /**
  754.      * Conditionally enables a drop-down list item at a given zero-relative index.
  755.      * @param index the zero-relative index of the drop-down list item
  756.      * @param cond true = enable the item, false = disable it
  757.      * @exception PropertyVetoException
  758.      * if the specified property value is unacceptable
  759.      */
  760.     public void setEnabled(int index, boolean cond) throws PropertyVetoException
  761.     {
  762.         list.setEnabled(index, cond);
  763.     }
  764.  
  765.     /**
  766.      * @deprecated
  767.      * @see #setEnabled(int, boolean)
  768.      * @exception PropertyVetoException
  769.      * if the specified property value is unacceptable
  770.      */
  771.     public void enable(int index, boolean cond) throws PropertyVetoException
  772.     {
  773.         setEnabled(index, cond);
  774.     }
  775.  
  776.     /**
  777.      * Deletes an item from the drop-down list.
  778.      * @param position the zero-relative index of the item
  779.      * @exception PropertyVetoException
  780.      * if the specified property value is unacceptable
  781.      * @see #delItems
  782.      * @see #addItem(java.lang.String)
  783.      * @see #addItem(java.lang.String, boolean)
  784.      * @see #addItem(java.awt.Image, java.lang.String)
  785.      * @see #addItem(java.awt.Image, java.lang.String, boolean)
  786.      * @see #setListItems(java.lang.String[])
  787.      */
  788.     public synchronized void delItem(int position) throws PropertyVetoException
  789.     {
  790.         list.delItem(position);
  791.  
  792.         if (list.countItems() == 0)
  793.         {
  794.             arrow.setEnabled(false);
  795.             dropList(false);
  796.         }
  797.         updateMaxNumChars();
  798.     }
  799.  
  800.     /**
  801.      * Deletes multiple items from the drop-down list.
  802.      * (Note: the end position must be greater than or equal to the start position.)
  803.      * @param start the starting zero-relative index of the items
  804.      * @param end the ending zero-relative index of the items
  805.      * @exception PropertyVetoException
  806.      * if the specified property value is unacceptable
  807.      * @see #delItem
  808.      * @see #addItem(java.lang.String)
  809.      * @see #addItem(java.lang.String, boolean)
  810.      * @see #addItem(java.awt.Image, java.lang.String)
  811.      * @see #addItem(java.awt.Image, java.lang.String, boolean)
  812.      * @see #setListItems(java.lang.String[])
  813.      */
  814.     public synchronized void delItems(int start, int end) throws PropertyVetoException
  815.     {
  816.         list.delItems(start, end);
  817.  
  818.         if (list.countItems() == 0)
  819.         {
  820.             arrow.setEnabled(false);
  821.             dropList(false);
  822.         }
  823.         updateMaxNumChars();
  824.     }
  825.  
  826.     /**
  827.      * Deletes the currently selected item from the list.
  828.      * @exception PropertyVetoException
  829.      * if the specified property value is unacceptable
  830.      * @see #addItem(java.lang.String)
  831.      * @see #addItem(java.lang.String, boolean)
  832.      * @see #addItem(java.awt.Image, java.lang.String)
  833.      * @see #addItem(java.awt.Image, java.lang.String, boolean)
  834.      * @see #setListItems(java.lang.String[])
  835.      */
  836.     public synchronized void delSelectedItem() throws PropertyVetoException
  837.     {
  838.         list.delSelectedItems();
  839.         updateMaxNumChars();
  840.     }
  841.  
  842.    /**
  843.      * Selects the drop-down list item with the specified zero-relative index.
  844.      * @param index the zero-relative index of the drop-down list item to select
  845.      * @exception PropertyVetoException
  846.      * if the specified property value is unacceptable
  847.      * @see #deselect
  848.      */
  849.     public synchronized void select(int index) throws PropertyVetoException
  850.     {
  851.         if (index >= 0 && index <= list.countItems())
  852.         {
  853.             list.setSelectedIndex(index, true);
  854.             editBox.setText(list.getSelectedItem());
  855.  
  856.             if (bOsFlag)
  857.             {
  858.                 repaint();
  859.             }
  860.         }
  861.     }
  862.  
  863.     /**
  864.      * Selects the first drop-down item in the list which has exactly matching text.
  865.      * @param str the String to match
  866.      * @exception PropertyVetoException
  867.      * if the specified property value is unacceptable
  868.      * @see #deselect
  869.      */
  870.     public void select(String str) throws PropertyVetoException
  871.     {
  872.         list.setSelectedItem(str, true);
  873.         editBox.setText(list.getSelectedItem());
  874.  
  875.         if (bOsFlag)
  876.         {
  877.             repaint();
  878.         }
  879.     }
  880.  
  881.     /**
  882.      * Deselects the drop-down list item at the specified zero-relative index.
  883.      * @param index the zero-relative index of the drop-down item to deselect
  884.      * @exception PropertyVetoException
  885.      * if the specified property value is unacceptable
  886.      * @see #select
  887.      */
  888.     public synchronized void deselect(int index) throws PropertyVetoException
  889.     {
  890.         list.setSelectedIndex(index, false);
  891.         editBox.setText("");
  892.     }
  893.  
  894.     /**
  895.      * Handles dropping and "un-dropping" the ComboBox list.
  896.      * @param isDown true to drop the list, false to "un-drop" the list.
  897.      * @exception PropertyVetoException
  898.      * if the specified property value is unacceptable
  899.      * @see #isListDown
  900.      */
  901.     public void setListDown(boolean isDown) throws PropertyVetoException
  902.     {
  903.         if (bDown != isDown)
  904.         {
  905.             Boolean oldValue = new Boolean(bDown);
  906.             Boolean newValue = new Boolean(isDown);
  907.  
  908.             vetos.fireVetoableChange("listDown", oldValue, newValue);
  909.  
  910.             bDown = isDown;
  911.  
  912.             if (bDown)
  913.             {
  914.                 list.show();
  915.                 vPad = 1;
  916.             }
  917.             else
  918.             {
  919.                 list.hide();
  920.                 vPad = 0;
  921.             }
  922.             reshapeInternals();
  923.             super.reshape(ix, iy, iwidth, lheight + arrowDim + vPad);
  924.             invalidate();
  925.  
  926.             changes.firePropertyChange("listDown", oldValue, newValue);
  927.         }
  928.     }
  929.  
  930.     /**
  931.      * Is the list up or down?
  932.      * @return true if the list is down, false if not.
  933.      * @see #setListDown
  934.      */
  935.     public boolean isListDown()
  936.     {
  937.         return bDown;
  938.     }
  939.  
  940.     /**
  941.      * @deprecated
  942.      * @see #setListDown
  943.      * @exception PropertyVetoException
  944.      * if the specified property value is unacceptable
  945.      */
  946.     public void dropList(boolean bDown) throws PropertyVetoException
  947.     {
  948.         setListDown(bDown);
  949.     }
  950.  
  951.     /**
  952.      * Moves and/or resizes this component.
  953.      * This is a standard Java AWT method which gets called to move and/or
  954.      * resize this component. Components that are in containers with layout
  955.      * managers should not call this method, but rely on the layout manager
  956.      * instead.
  957.      *
  958.      * @param x horizontal position in the parent's coordinate space
  959.      * @param y vertical position in the parent's coordinate space
  960.      * @param width the new width
  961.      * @param height the new height
  962.      */
  963.     public synchronized void reshape(int x, int y, int width, int height)
  964.     {
  965.         super.reshape(x, y, width, height);
  966.  
  967.         ix        = x;
  968.         iy        = y;
  969.         iwidth    = width;
  970.  
  971.         reshapeInternals();
  972.     }
  973.  
  974.     /**
  975.      * Paints this component using the given graphics context.
  976.      * This is a standard Java AWT method which typically gets called
  977.      * by the AWT to handle painting this component. It paints this component
  978.      * using the given graphics context. The graphics context clipping region
  979.      * is set to the bounding rectangle of this component and its [0,0]
  980.      * coordinate is this component's top-left corner.
  981.      *
  982.      * @param g the graphics context used for painting
  983.      * @see java.awt.Component#repaint
  984.      * @see java.awt.Component#update
  985.      */
  986.     public void paint(Graphics g)
  987.     {
  988.         super.paint(g);
  989.  
  990.         reshapeInternals();
  991.     }
  992.  
  993.     /**
  994.      * Returns the recommended dimensions to properly display this component.
  995.      * This is a standard Java AWT method which gets called to determine
  996.      * the recommended size of this component.
  997.      * Preferred size is .
  998.      *
  999.      * @see #getMinimumSize
  1000.      */
  1001.     public Dimension getPreferredSize()
  1002.     {
  1003.         reshapeInternals();
  1004.         
  1005.         int editBoxPreferredWidth = editBox.getPreferredSize(maxNumChars).width;
  1006.  
  1007.         if(bDown)
  1008.             return new Dimension(editBoxPreferredWidth + arrowDim + hPad, arrowDim + vPad + lheight);
  1009.         else
  1010.             return new Dimension(editBoxPreferredWidth + arrowDim + hPad, arrowDim);
  1011.     }
  1012.  
  1013.     /**
  1014.      * Returns the minimum dimensions to properly display this component.
  1015.      * This is a standard Java AWT method which gets called to determine
  1016.      * the minimum size of this component.
  1017.      * Returns the results of a call to getPreferredSize.
  1018.      * @see #getPreferredSize
  1019.      */
  1020.     public Dimension getMinimumSize()
  1021.     {
  1022.         return getPreferredSize();
  1023.     }
  1024.  
  1025.     /**
  1026.      * Sets the command name of the action event fired by this button.
  1027.      * @param command The name of the action event command fired by this button
  1028.      * @exception PropertyVetoException
  1029.      * if the specified property value is unacceptable
  1030.      */
  1031.     public void setActionCommand(String command) throws PropertyVetoException
  1032.     {
  1033.         String oldValue = actionCommand;
  1034.  
  1035.         vetos.fireVetoableChange("actionCommand", oldValue, command);
  1036.         actionCommand = command;
  1037.         changes.firePropertyChange("actionCommand", oldValue, command);
  1038.     }
  1039.  
  1040.     /**
  1041.      * @return the command name of the action event fired by this button.
  1042.      */
  1043.     public String getActionCommand()
  1044.     {
  1045.         return actionCommand;
  1046.     }
  1047.  
  1048.     /**
  1049.      * Tells this component that it has been added to a container.
  1050.      * This is a standard Java AWT method which gets called by the AWT when
  1051.      * this component is added to a container. Typically, it is used to
  1052.      * create this component's peer.
  1053.      *
  1054.      * It has been overridden here to hook-up event listeners.
  1055.      *
  1056.      * @see #removeNotify
  1057.      */
  1058.     public synchronized void addNotify()
  1059.     {
  1060.         super.addNotify();
  1061.  
  1062.         //Hook up listeners
  1063.         if (mouse == null)
  1064.         {
  1065.             mouse = new Mouse();
  1066.             list.addMouseListener(mouse);
  1067.             editBox.addMouseListener(mouse);
  1068.         }
  1069.         if (keyList == null)
  1070.         {
  1071.             keyList = new KeyList();
  1072.             list.addKeyListener(keyList);
  1073.         }
  1074.         if (keyBox == null)
  1075.         {
  1076.             keyBox = new KeyBox();
  1077.             editBox.addKeyListener(keyBox);
  1078.         }
  1079.         if (item == null)
  1080.         {
  1081.             item = new Item();
  1082.             list.addItemListener(item);
  1083.         }
  1084.         if (action == null)
  1085.         {
  1086.             action = new Action();
  1087.             arrow.addActionListener(action);
  1088.         }
  1089.         if (focus == null)
  1090.         {
  1091.             focus = new Focus();
  1092.             addFocusListener(focus);
  1093.             arrow.addFocusListener(focus);
  1094.             editBox.addFocusListener(focus);
  1095.         }
  1096.     }
  1097.  
  1098.     /**
  1099.      * Tells this component that it is being removed from a container.
  1100.      * This is a standard Java AWT method which gets called by the AWT when
  1101.      * this component is removed from a container. Typically, it is used to
  1102.      * destroy the peers of this component and all its subcomponents.
  1103.      *
  1104.      * It has been overridden here to unhook event listeners.
  1105.      *
  1106.      * @see #addNotify
  1107.      */
  1108.     public synchronized void removeNotify()
  1109.     {
  1110.         //Unhook listeners
  1111.         if (mouse != null)
  1112.         {
  1113.             list.removeMouseListener(mouse);
  1114.             editBox.removeMouseListener(mouse);
  1115.             mouse = null;
  1116.         }
  1117.         if (keyList != null)
  1118.         {
  1119.             list.removeKeyListener(keyList);
  1120.             keyList = null;
  1121.         }
  1122.         if (keyBox != null)
  1123.         {
  1124.             editBox.removeKeyListener(keyBox);
  1125.             keyBox = null;
  1126.         }
  1127.         if (item != null)
  1128.         {
  1129.             list.removeItemListener(item);
  1130.             item = null;
  1131.         }
  1132.         if (action != null)
  1133.         {
  1134.             arrow.removeActionListener(action);
  1135.             action = null;
  1136.         }
  1137.         if (focus != null)
  1138.         {
  1139.             removeFocusListener(focus);
  1140.             arrow.removeFocusListener(focus);
  1141.             editBox.removeFocusListener(focus);
  1142.             focus = null;
  1143.         }
  1144.  
  1145.         super.removeNotify();
  1146.     }
  1147.  
  1148.     /**
  1149.      * Takes no action.
  1150.      * This is a standard Java AWT method which gets called to specify
  1151.      * which layout manager should be used to layout the components in
  1152.      * standard containers.
  1153.      *
  1154.      * Since layout managers CANNOT BE USED with this container the standard
  1155.      * setLayout has been OVERRIDDEN for this container and does nothing.
  1156.      *
  1157.      * @param lm the layout manager to use to layout this container's components
  1158.      * (IGNORED)
  1159.      * @see java.awt.Container#getLayout
  1160.      **/
  1161.     public void setLayout(LayoutManager lm)
  1162.     {
  1163.     }
  1164.  
  1165.     public void validate()
  1166.     {
  1167.         super.validate();
  1168.  
  1169.         reshapeInternals();
  1170.     }
  1171.  
  1172.     /**
  1173.      * Adds the specified action listener to receive action events
  1174.      * @param l the action listener
  1175.      */
  1176.     public synchronized void addActionListener(ActionListener l)
  1177.     {
  1178.         actionListener = AWTEventMulticaster.add(actionListener, l);
  1179.     }
  1180.  
  1181.     /**
  1182.      * Removes the specified action listener so it no longer receives
  1183.      * action events.
  1184.      * @param l the action listener
  1185.      */
  1186.     public synchronized void removeActionListener(ActionListener l)
  1187.     {
  1188.         actionListener = AWTEventMulticaster.remove(actionListener, l);
  1189.     }
  1190.  
  1191.     /**
  1192.      * Adds a listener for all event changes.
  1193.      * @param listener the listener to add.
  1194.      * @see #removePropertyChangeListener
  1195.      */
  1196.     public synchronized void addPropertyChangeListener(PropertyChangeListener listener)
  1197.     {
  1198.         changes.addPropertyChangeListener(listener);
  1199.     }
  1200.  
  1201.     /**
  1202.      * Removes a listener for all event changes.
  1203.      * @param listener the listener to remove.
  1204.      * @see #addPropertyChangeListener
  1205.      */
  1206.     public synchronized void removePropertyChangeListener(PropertyChangeListener listener)
  1207.     {
  1208.         changes.removePropertyChangeListener(listener);
  1209.     }
  1210.  
  1211.     /**
  1212.      * Adds a vetoable listener for all event changes.
  1213.      * @param listener the listener to add.
  1214.      * @see #removeVetoableChangeListener
  1215.      */
  1216.     public synchronized void addVetoableChangeListener(VetoableChangeListener listener)
  1217.     {
  1218.         vetos.addVetoableChangeListener(listener);
  1219.     }
  1220.  
  1221.     /**
  1222.      * Removes a vetoable listener for all event changes.
  1223.      * @param listener the listener to remove.
  1224.      * @see #addVetoableChangeListener
  1225.      */
  1226.     public synchronized void removeVetoableChangeListener(VetoableChangeListener listener)
  1227.     {
  1228.         vetos.removeVetoableChangeListener(listener);
  1229.     }
  1230.  
  1231.     /**
  1232.      * This is the Mouse Event handling innerclass.
  1233.      */
  1234.     class Mouse extends java.awt.event.MouseAdapter implements java.io.Serializable
  1235.     {
  1236.         boolean wasPressed = false;
  1237.  
  1238.         /**
  1239.          * Handles Mouse Entered events
  1240.          * @param e the MouseEvent
  1241.          */
  1242.         public void mouseEntered(MouseEvent e)
  1243.         {
  1244.             Object source = e.getSource();
  1245.             if(source == list)
  1246.                 bOverList = true;
  1247.         }
  1248.  
  1249.         /**
  1250.          * Handles Mouse Exited events
  1251.          * @param e the MouseEvent
  1252.          */
  1253.         public void mouseExited(MouseEvent e)
  1254.         {
  1255.             //We are only listening to the list...
  1256.             bOverList = false;
  1257.         }
  1258.  
  1259.         public void mousePressed(MouseEvent e)
  1260.         {
  1261.             Object source = e.getSource();
  1262.             if(source == editBox)
  1263.             {
  1264.                 wasPressed = true;
  1265.             }
  1266.             else
  1267.                 wasPressed = false;
  1268.         }
  1269.  
  1270.         public void mouseReleased(MouseEvent e)
  1271.         {
  1272.             Object source = e.getSource();
  1273.             if(source == editBox && wasPressed && !(bEditable || bSearchable))
  1274.             {
  1275.                 try
  1276.                 {
  1277.                     setListDown(!bDown);
  1278.                 }
  1279.                 catch (PropertyVetoException exc) {}
  1280.             }
  1281.             wasPressed = false;
  1282.         }
  1283.     }
  1284.  
  1285.     /**
  1286.      * This is the Adjustment Event handling innerclass.
  1287.      */
  1288.     class Action implements java.awt.event.ActionListener, java.io.Serializable
  1289.     {
  1290.         /**
  1291.          * Handles Action events
  1292.          * @param e the ActionEvent
  1293.          */
  1294.         public void actionPerformed(ActionEvent e)
  1295.         {
  1296.             Object source = e.getSource();
  1297.  
  1298.             if(source instanceof DirectionButton)
  1299.             {
  1300.                 try
  1301.                 {
  1302.                     setListDown(!bDown);
  1303.                 }
  1304.                 catch (PropertyVetoException exc) {}
  1305.             }
  1306.             else if(e.getActionCommand().equals("ImageSelected"))
  1307.             {
  1308.                 sourceActionEvent("ImageSelected");
  1309.             }
  1310.         }
  1311.     }
  1312.  
  1313.     /**
  1314.      * This is the Key Event handling innerclass for handling
  1315.      * KeyEvents from the editBox.
  1316.      */
  1317.     class KeyBox extends java.awt.event.KeyAdapter implements java.io.Serializable
  1318.     {
  1319.         /**
  1320.          * Handles Key Pressed events
  1321.          * @param e the KeyEvent
  1322.          */
  1323.         public void keyPressed(KeyEvent e)
  1324.         {
  1325.             sLastText = editBox.getText();
  1326.         }
  1327.  
  1328.         /**
  1329.          * Handles Key Released events
  1330.          * @param e the KeyEvent
  1331.          */
  1332.         public void keyReleased(KeyEvent e)
  1333.         {
  1334.             verify();
  1335.         }
  1336.     }
  1337.  
  1338.     /**
  1339.      * This is the Key Event handling innerclass for handling
  1340.      * KeyEvents from the list.
  1341.      */
  1342.     class KeyList extends java.awt.event.KeyAdapter implements java.io.Serializable
  1343.     {
  1344.         /**
  1345.          * Handles Key Pressed events
  1346.          * @param e the KeyEvent
  1347.          */
  1348.         public void keyPressed(KeyEvent e)
  1349.         {
  1350.             sLastText = editBox.getText();
  1351.         }
  1352.  
  1353.         /**
  1354.          * Handles Key Released events
  1355.          * @param e the KeyEvent
  1356.          */
  1357.         public void keyReleased(KeyEvent e)
  1358.         {
  1359.             //We are only listening to the list...
  1360.             switch(e.getKeyCode())
  1361.             {
  1362.                 case KeyEvent.VK_HOME:
  1363.                     try { list.setSelectedIndex(0, true); } catch(PropertyVetoException exc) {}
  1364.                     break;
  1365.                 case KeyEvent.VK_END:
  1366.                     try { list.setSelectedIndex(list.countItems() - 1, true); } catch(PropertyVetoException exc) {}
  1367.                     break;
  1368.                 case KeyEvent.VK_PAGE_UP:
  1369.                 case KeyEvent.VK_UP:
  1370.                     try { list.setSelectedIndex(list.getSelectedIndex() - 1, true); } catch(PropertyVetoException exc) {}
  1371.                     break;
  1372.                 case KeyEvent.VK_PAGE_DOWN:
  1373.                 case KeyEvent.VK_DOWN:
  1374.                     try { list.setSelectedIndex(list.getSelectedIndex() + 1, true); } catch(PropertyVetoException exc) {}
  1375.                     break;
  1376.             }
  1377.             editBox.setText(list.getSelectedItem());
  1378.             editBox.selectAll();
  1379.             verify();
  1380.         }
  1381.     }
  1382.  
  1383.     /**
  1384.      * This is the Focus Event handling innerclass.
  1385.      */
  1386.     class Focus implements java.awt.event.FocusListener, java.io.Serializable
  1387.     {
  1388.         /**
  1389.          * Handles Focus Gained events
  1390.          * @param e the FocusEvent
  1391.          */
  1392.         public void focusGained(FocusEvent e)
  1393.         {
  1394.             Object source = e.getSource();
  1395.             if (source instanceof ComboBox && !bDown)
  1396.             {
  1397.                 editBox.selectAll();
  1398.                 editBox.requestFocus();
  1399.             }
  1400.  
  1401.             if (bOsFlag)
  1402.             {
  1403.                 if (source == editBox)
  1404.                 {
  1405.                     try
  1406.                     {
  1407.                         setListDown(false);
  1408.                     }
  1409.                     catch (PropertyVetoException exc) {}
  1410.                 }
  1411.             }
  1412.         }
  1413.  
  1414.         /**
  1415.          * Handles Focus Lost events
  1416.          * @param e the FocusEvent
  1417.          */
  1418.         public void focusLost(FocusEvent e)
  1419.         {
  1420.             if ((e.getSource() == arrow) && !bOverList)
  1421.             {
  1422.                 try
  1423.                 {
  1424.                     setListDown(false);
  1425.                 }
  1426.                 catch (PropertyVetoException exc) {}
  1427.             }
  1428.         }
  1429.     }
  1430.  
  1431.     /**
  1432.      * This is the Item Event handling innerclass.
  1433.      */
  1434.     class Item implements java.awt.event.ItemListener, java.io.Serializable
  1435.     {
  1436.         /**
  1437.          * Handles Item State Changed events
  1438.          * @param e the ItemEvent
  1439.          */
  1440.         public void itemStateChanged(ItemEvent e)
  1441.         {
  1442.             editBox.setText(list.getSelectedItem());
  1443.             sourceActionEvent();
  1444.             try
  1445.             {
  1446.                 setListDown(false);
  1447.             }
  1448.             catch (PropertyVetoException exc) {}
  1449.         }
  1450.     }
  1451.  
  1452.     /**
  1453.      * Fire an action event to the listeners
  1454.      * @param command the string containing the command to send
  1455.      * with the event.
  1456.      * @see #sourceActionEvent()
  1457.      */
  1458.     protected void sourceActionEvent(String command)
  1459.     {
  1460.         if (actionListener != null)
  1461.             actionListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, command));
  1462.     }
  1463.  
  1464.     /**
  1465.      * Fire an action event to the listeners
  1466.      * with the actionCommand
  1467.      * @see #sourceActionEvent(java.lang.String)
  1468.      */
  1469.     protected void sourceActionEvent()
  1470.     {
  1471.         sourceActionEvent(actionCommand);
  1472.     }
  1473.  
  1474.     /**
  1475.      * Used to calculate the preferred size of the text field to 
  1476.      * determine overall preferred size.
  1477.      * Should be called after any manipulation of the list items.
  1478.      * @see #getPreferredSize
  1479.      */
  1480.     protected void updateMaxNumChars()
  1481.     {
  1482.         maxNumChars = 0;
  1483.         String[] listItems = getListItems();
  1484.         if(listItems != null)
  1485.         {
  1486.             int listLength = listItems.length;
  1487.             for (int i = 0; i < listLength; ++i)
  1488.             {
  1489.                 maxNumChars = Math.max(listItems[i].length(), maxNumChars);
  1490.             }
  1491.         }
  1492.     }
  1493.     
  1494.     /**
  1495.      * A utility routine to resize the sub-components that make up a ComboBox.
  1496.      */
  1497.     protected void reshapeInternals()
  1498.     {
  1499.         Dimension    s                        = size();
  1500.         Dimension    arrowSize                = arrow.getPreferredSize();
  1501.         Dimension    editBoxPreferredSize    = editBox.getPreferredSize();
  1502.  
  1503.         arrowDim = Math.max(arrowSize.width, arrowSize.height);
  1504.  
  1505.         if (editBoxPreferredSize.height > arrowDim)
  1506.             arrowDim = editBoxPreferredSize.height;
  1507.  
  1508.         editBox.reshape(0,0, s.width - 1 - arrowDim - hPad, editBoxPreferredSize.height);
  1509.  
  1510.         arrow.setBounds(s.width - arrowDim, 0, arrowDim, arrowDim);
  1511.         arrow.shrinkTriangle(1, 1, 4, 3);
  1512.  
  1513.         if (bDown)
  1514.         {
  1515.             if (getParent() != null)
  1516.             {
  1517.                 int availableHeight = getParent().bounds().height - iy - arrowDim - vPad;
  1518.                 int preferredHeight = list.getMinimumSize().height;
  1519.                 
  1520.                 if(availableHeight < preferredHeight)
  1521.                 {
  1522.                     //Get the height of the number of rows that will fit in the available height.
  1523.                     lheight = list.getMinimumSize( (availableHeight - list.getBorderWidth()) / list.getCellHeight() ).height;
  1524.                 }
  1525.                 else
  1526.                 {
  1527.                     lheight = preferredHeight;
  1528.                 }
  1529.             }
  1530.             else
  1531.             {
  1532.                 lheight = list.getMinimumSize().height;
  1533.             }
  1534.  
  1535.             list.reshape(0, arrowDim + vPad, s.width, lheight);
  1536.         }
  1537.         else
  1538.             lheight = 0;
  1539.     }
  1540.  
  1541.     /**
  1542.      * Verify that at least one list item starts with the edit field's text.
  1543.      * If a match is found, the edit field's text is set to that item's value.
  1544.      * This is done only if searching is enabled.
  1545.      */
  1546.     protected void verify()
  1547.     {
  1548.         if (bSearchable == true)
  1549.         {
  1550.             searchIndex = editBox.getSelectionStart();
  1551.             sSearchOrig = editBox.getText().substring(0, searchIndex);
  1552.  
  1553.             if (bCaseSensitive)
  1554.             {
  1555.                 sSearchText = sSearchOrig;
  1556.             }
  1557.             else
  1558.             {
  1559.                 sSearchText = sSearchOrig.toUpperCase();
  1560.             }
  1561.  
  1562.             searchLen = list.countItems();
  1563.             searchI = 0;
  1564.             int stLength = sSearchText.length();
  1565.             int matchIndex = 0;
  1566.             int maxMatch = 0;
  1567.             String matchString;
  1568.             String matchItem = "";
  1569.             boolean isBreak;
  1570.             
  1571.             if (stLength > 0)
  1572.             {
  1573.                 while(searchI < searchLen)
  1574.                 {
  1575.                     if (bCaseSensitive)
  1576.                     {
  1577.                         sSearchItem = list.getText(searchI);
  1578.                     }
  1579.                     else
  1580.                     {
  1581.                         sSearchItem = list.getText(searchI).toUpperCase();
  1582.                     }
  1583.                     
  1584.                     isBreak = false;
  1585.                     matchIndex = 1;
  1586.                     while(matchIndex <= stLength)
  1587.                     {
  1588.                         matchString = sSearchText.substring(0, matchIndex);
  1589.                         if (sSearchItem.startsWith(matchString))
  1590.                         {
  1591.                             try { list.setSelectedIndex(searchI, true); } catch(PropertyVetoException e) {}
  1592.                             if(maxMatch < matchIndex)
  1593.                             {
  1594.                                 maxMatch = matchIndex;
  1595.                                 matchItem = sSearchItem;
  1596.                             }
  1597.                             isBreak = true;
  1598.                             ++matchIndex;
  1599.                         }
  1600.                         else //It doesn't match.  Go on to the next list item...
  1601.                         {
  1602.                             isBreak = false;
  1603.                             ++searchI;
  1604.                             break;
  1605.                         }
  1606.                     }
  1607.                      if(isBreak)
  1608.                      {
  1609.                         break;
  1610.                     }
  1611.                }
  1612.  
  1613.                 if (!bEditable)    //if not editable and 
  1614.                 {
  1615.                      editBox.setText(matchItem);
  1616.                        if(searchI == searchLen)    //search failed
  1617.                     {
  1618.                         editBox.select(maxMatch, maxMatch);                        
  1619.                     }
  1620.                     else    //search success
  1621.                     {
  1622.                         editBox.select(searchIndex, searchIndex);                        
  1623.                     }
  1624.                     
  1625.                     //If the cursor is at the beginning of the box there should be nothing found...
  1626.                     if (editBox.getSelectionStart() == 0)
  1627.                         editBox.setText("");
  1628.                 }
  1629.             }
  1630.             
  1631.         }
  1632.  
  1633.         sLastText = editBox.getText();
  1634.         
  1635.     }
  1636.  
  1637.     /**
  1638.      * The command name of the action event fired by this component.
  1639.      */
  1640.     protected String actionCommand;
  1641.     /**
  1642.      * The action listener to keep track of listeners for our action event.
  1643.      */
  1644.     protected ActionListener actionListener = null;
  1645.  
  1646.     /** The text field part of this ComboBox.
  1647.     */
  1648.     protected TextField            editBox;
  1649.     /** The button on the right part of this ComboBox that controls dopping the list.
  1650.     */
  1651.     protected DirectionButton        arrow;
  1652.     /** The list part of this ComboBox.
  1653.     */
  1654.     protected ImageListBox            list;
  1655.     /**
  1656.      * The number of characters of the longest item in the list.
  1657.      * Used to calculate preferred size.
  1658.      * @see #updateMaxNumChars
  1659.      */
  1660.     protected int maxNumChars = 0;
  1661.     /** True if the mouse is over the ComboBox.
  1662.     */
  1663.     transient protected boolean bOverList   = false;
  1664.     /** True if the list is currently dropped (displayed).
  1665.     */
  1666.     transient protected boolean bDown = false;
  1667.     /** The latest user-entered text.
  1668.     */
  1669.     transient protected String  sLastText;
  1670.  
  1671.     /** If true this ComboBox has a user-editable text field.
  1672.     */
  1673.     protected boolean                bEditable;
  1674.     /** If true this ComboBox is searchable.
  1675.     */
  1676.     protected boolean                bSearchable;
  1677.     /** If true search compares are case-sensitive.
  1678.     */
  1679.     protected boolean                bCaseSensitive;
  1680.     /** The x parameter value in the latest reshape() call.
  1681.     */
  1682.     protected int                    ix;
  1683.     /** The y parameter value in the latest reshape() call.
  1684.     */
  1685.     protected int                    iy;
  1686.     /** The width parameter value in the latest reshape() call.
  1687.     */
  1688.     protected int                    iwidth;
  1689.     /** The current height of the list.
  1690.     */
  1691.     protected int                    lheight;
  1692.     /** The dimension of the arrow button.
  1693.     */
  1694.     protected int                    arrowDim;
  1695.     /** The distance between the direction button and the edit text box.
  1696.     */
  1697.     protected int                    hPad;
  1698.     /** The distance between the edit text box and the drop down list.
  1699.     */
  1700.     protected int                    vPad;
  1701.     /** If true the horizontal scroll bar is shown as needed.
  1702.     */
  1703.     protected boolean                showHScroll = false;
  1704.     /** If true the vertical scroll bar is shown as needed.
  1705.     */
  1706.     protected boolean                showVScroll = true;
  1707.     /** True if running under Windows.
  1708.     */
  1709.     transient protected static boolean        bOsFlag;
  1710.     /** The case-normalized user-entered string used to match during searches.
  1711.     */
  1712.     protected String                sSearchText;
  1713.     /** The list item string used to match during searches.
  1714.     */
  1715.     protected String                sSearchItem;
  1716.     /** The user-entered string used to match during searches.
  1717.     * Not case normalized.
  1718.     */
  1719.     protected String                sSearchOrig;
  1720.     /** Where the selected area starts in the user-entered text.
  1721.     */
  1722.     protected int                    searchIndex;
  1723.     /** The number of items in the list to seach (all).
  1724.     */
  1725.     protected int                    searchLen;
  1726.     /** The list item currently being checked for search match.
  1727.     */
  1728.     protected int                    searchI;
  1729.  
  1730.     private Mouse        mouse    = null;
  1731.     private KeyList    keyList    = null;
  1732.     private KeyBox        keyBox    = null;
  1733.     private Action        action    = null;
  1734.     private Focus        focus    = null;
  1735.     private Item        item    = null;
  1736.  
  1737.     private VetoableChangeSupport    vetos = new VetoableChangeSupport(this);
  1738.  
  1739.     private PropertyChangeSupport    changes = new PropertyChangeSupport(this);
  1740.  
  1741.     static
  1742.     {
  1743.         bOsFlag = !symantec.itools.lang.OS.isWindows() && !symantec.itools.lang.OS.isMacintosh();
  1744.     }
  1745. }
  1746.  
  1747.